<script setup lang="ts">
import { computed, nextTick, onBeforeMount, reactive, ref, unref } from 'vue'
import type {
  VxeGridConstructor,
  VxeGridDefines,
  VxeGridProps,
  VxeTableInstance,
  VxeToolbarInstance,
  VxeToolbarProps
} from 'vxe-table'
import type {
  BusinessUIAction,
  BusinessUIFormType,
  BusinessUIQueryType,
  BusinessUITableType,
  DicType
} from '@/types/custom'
import { storeToRefs } from 'pinia'
import { useAppState } from '@/stores/appState'
import {
  columnFilterMethod,
  formatColRows,
  initFooterMethod,
  initFormatColumns,
  initGridProps,
  removeGridColumns,
  setGridColumns
} from '@/views/components/grid/libs'
import { useRoute } from 'vue-router'
import { useBaseApi } from '@/api/base'
import { Sell, SoldOut } from '@element-plus/icons-vue'
import { themeConfig } from '@/storage'
import { assign, clone, isNumber, parseUrl } from 'xe-utils'
import { ElLoadingService, ElMessage, ElMessageBox } from 'element-plus'

import TemplateQuery from '@/views/components/form/TemplateQuery.vue'
import ProductViewModal from '@/views/wh/component/ProductViewModal.vue'
import { getColumnTips } from '@/utils/custom'
import mittBus from '@/utils/mitt'

interface RowType {
  created_on: string
  dep_id: string
  dep_name: string
  files: TypedAny[]
  id: string
  is_dis: boolean
  modified_on: string
  name: string
  org_id: string
  org_name: string
  own_division: string
  own_division_name: string
  own_user: string
  sex: string
}

const modelValue = defineModel<string>()

const route = useRoute()

const { mobile } = storeToRefs(useAppState())

const { get_business_ui } = useBaseApi()
const { CustomRequest } = useBaseApi()

// 表格
const gridRef = ref<VxeTableInstance>()
// 表格工具栏
const toolbarRef = ref<VxeToolbarInstance>()
// 查询栏
const queryRef = ref()
// 弹窗
const modalRef = ref()

const loading = ref(false)
const params = ref<TypedAny>({})
const gridOptions = ref<VxeGridProps<RowType>>({})
// 表格
const uiTable = ref<BusinessUITableType | undefined>()
// 表格
const uiForm = ref<BusinessUIFormType | undefined>()
// 查询栏
const uiQuery = ref<BusinessUIQueryType | undefined>()
// 表单字典
const dicTable = ref<DicType[]>([])
// 查询字典
const dicQuery = ref<DicType[]>([])
// 按钮配置
const uiActions = ref<BusinessUIAction[]>([])
// 工具栏配置
const toolbarConfig = ref<VxeToolbarProps>({})
// 表格分页
const gridPage = reactive({
  total: 0,
  page: 1,
  pageSize: 50
})
// 数据
const gridData = ref<TypedAny[]>([])
// 合计
const queryNum = ref(0)
// 当前查询栏参数
let queryParams: TypedAny | undefined

/**
 * 主键
 */
const keyField = computed(() => uiTable.value?.default_value_parse.keyField || 'id')

// 内嵌按钮
const embeddedUIActions = computed(() => {
  return uiActions.value?.filter((f) => !f.global) || []
})
// 顶部表格按钮偏移量
const rightSpacing = computed(() => {
  const config: TypedAny = unref(toolbarConfig)
  const { globalComponentSize } = unref(themeConfig)
  let length = 0
  for (const k in config) {
    if (!['enabled', 'zoom'].includes(k) && config[k]) {
      length += 1
    }
  }
  let size = 31
  if (globalComponentSize === 'mini') {
    size = 31
  } else if (globalComponentSize === 'default') {
    size = 35
  } else if (globalComponentSize === 'large') {
    size = 38
  }
  return length * size
})

/**
 * 获取业务详情
 */
const onFetchBusiness = async () => {
  loading.value = true
  const business_id = unref(modelValue)
  if (!business_id) return Promise.reject(false)
  const { data } = await get_business_ui(business_id)

  if (!data.ui_table) return Promise.reject(false)

  uiQuery.value = data.ui_query
  uiForm.value = data.ui_form
  dicTable.value = data.dic_table || []
  uiActions.value = data.actions || []
  dicQuery.value = data.dic_query || []

  if (data.ui_table) {
    const { default_value_parse } = data.ui_table
    if (default_value_parse.toolbarConfig) toolbarConfig.value = default_value_parse.toolbarConfig
    uiTable.value = data.ui_table
  }

  // 加载数据
  // await onFetch()

  // 格式化表格配置
  gridOptions.value = initGridProps({
    uiForm: data.ui_form,
    uiTable: data.ui_table,
    filename: route.meta.title,
    exportConfig: {
      remote: true,
      exportMethod: async (option) => {
        const { $table, options } = option

        // 全量数据
        if (options.mode === 'all') {
          options.data = await onFetchAll()
        }

        // 必须关闭服务器端导出，不然会死循环
        options.remote = false

        // 导出
        return $table.exportData(options)
      }
    }
  })

  const cols = await initFormatColumns({
    uiForm: data.ui_form,
    uiTable: data.ui_table,
    dicTable: data.dic_table,
    uiActions: data.actions
  })

  // 初始化表尾合计
  initFooterMethod(unref(gridOptions), cols)

  gridOptions.value.columns = cols

  // loading.value = false

  // 将表格和工具栏进行关联
  await nextTick(() => {
    const $grid = gridRef.value
    const $toolbar = toolbarRef.value
    if ($grid && $toolbar) {
      $grid.connect($toolbar)
    }
  })
}

const setCustomColumns = ($grid: VxeGridConstructor) => {
  const table = unref(uiTable)
  if (table) {
    const { fullColumn } = $grid.getTableColumn()
    const cols = fullColumn
      .filter((column) => columnFilterMethod({ column }))
      .map((v, seq) => {
        return {
          type: v.type,
          field: v.field,
          fixed: v.fixed,
          visible: v.visible,
          width: v.renderWidth,
          seq
        }
      })
    setGridColumns(table, cols)
  }
}

const onCustomChange = ({ $grid, type }: VxeGridDefines.CustomEventParams) => {
  if (uiTable.value) {
    if (type === 'reset') {
      removeGridColumns(uiTable.value)
      onFetch()
    } else if (type === 'confirm') {
      setCustomColumns($grid)
    }
  }
}

const onResizableChange = ({ $grid }: VxeGridDefines.ResizableChangeEventParams) => {
  if (uiTable.value) {
    setCustomColumns($grid)
  }
}

/**
 * 工具栏查询
 * @param params
 */
const onToolFetch = (params?: TypedAny) => {
  queryParams = params || {}
  onFetch()
}

/**
 * 查询
 */
const onFetch = async () => {
  if (!uiTable.value) return Promise.reject('没有表格配置')
  loading.value = true
  try {
    const { api, method } = uiTable.value

    const param = Object.assign({}, gridPage, queryParams, unref(params))

    const config = {
      url: api,
      method: method,
      params: method === 'get' ? param : unref(params),
      data: method === 'post' ? param : undefined
    }

    const { data } = await CustomRequest(config)

    // 总数
    if (data && isNumber(data.total)) gridPage.total = data.total

    const list = data.items || []

    list.forEach((v: TypedAny) => {
      v.set_type_count = v.set_type
    })

    formatColRows({
      rows: list,
      uiTable: uiTable.value,
      uiForm: uiForm.value,
      dicTable: dicTable.value
    })
    gridData.value = list
    loading.value = false


    // 库存合计量
    const par = parseUrl(api)
    const searchQuery = par.searchQuery || {}
    const res = await CustomRequest({
      url: '/api-mis/WareHouseInventory/inventory_query_sum',
      method: 'post',
      params: searchQuery,
      data: config.data
    })
    queryNum.value = res.data || 0

  } catch (e) {
    loading.value = false
  }
}

/**
 * 导出全量数据
 */
const onFetchAll = async () => {
  const table = unref(uiTable)
  if (!table) return []
  const loadingInstance = ElLoadingService({
    fullscreen: true,
    text: '加载中...',
    body: true
  })
  try {
    const list: any[] = []
    const count = Math.ceil(gridPage.total / 1000)
    const { api, method } = table
    const param: TypedAny = Object.assign({}, gridPage, queryParams, unref(params))
    param.pageSize = 1000
    for (let i = 1; i <= count; i++) {
      loadingInstance.text.value = `正在获取数据${i}/${count}，请耐心等待。`
      param.page = i

      const { data } = await CustomRequest({
        url: api,
        method: method,
        params: method === 'get' ? param : unref(params),
        data: method === 'post' ? param : undefined
      })

      const items = data ? data.items || [] : []
      list.push(...items)
    }
    formatColRows({
      rows: list,
      uiTable: uiTable.value,
      uiForm: uiForm.value,
      dicTable: dicTable.value,
      // excel会把null格式化成字符串，所以必须删掉null换成''
      isDeleteNull: true
    })
    loadingInstance.close()
    return list
  } catch (e) {
    loadingInstance.close()
    return []
  }
}

/**
 * 操作
 * @param action
 * @param row
 */
const onAction = (action: BusinessUIAction, row?: TypedAny) => {
  if (action.action === 'Udp') {
    handleSoldOut(row)
  } else if (action.action === 'Del') {
    handleSoldRemove(action, row)
  } else if (action.api) {
    onActionRequest(action)
  }
}

/**
 * 按钮请求
 */
const onActionRequest = async (action: BusinessUIAction, params?: TypedAny) => {
  const config = {
    url: action?.api,
    method: action?.method || 'post',
    params: {},
    data: {}
  }
  const action_parse = clone(action?.default_value_parse || {}, true)
  const c_params = clone(params || {}, true)
  const default_value_parse = assign(action_parse, c_params)
  if (!params) {
    const radio = gridRef.value?.getRadioRecord()
    const records = gridRef.value?.getCheckboxRecords() || []
    if (radio) {
      default_value_parse.row = radio[unref(keyField)] || undefined
    } else if (records.length) {
      if (['get', 'delete'].includes(config.method)) {
        // 字符串传参
        default_value_parse.rows = records.map((v: TypedAny) => v[unref(keyField)]).join(',')
      } else {
        // 数组传参
        default_value_parse.rows = records.map((v: TypedAny) => v[unref(keyField)])
      }
    } else if (action?.model === 'trigger') {
      ElMessage.warning('未勾选')
      return Promise.resolve()
    }
  }

  config.params = default_value_parse
  config.data = default_value_parse

  return CustomRequest(config)
    .then(({ data }) => {
      if (action?.action === 'ExportJson') {
        gridRef.value?.saveFile({
          filename: route.meta.title || 'JSON',
          type: 'json',
          content: JSON.stringify({ rows: data })
        })
      } else {
        onFetch()
      }
      ElMessage.success(`${action?.name} 成功`)
    })
    .finally(() => {
      loading.value = false
    })
}

const handleSoldRemove = (action: BusinessUIAction, row?: TypedAny) => {
  if (!uiForm.value || !row) return
  const tips = getColumnTips(uiTable.value?.columns || [], row)
  const actionName = action.name
  const { api } = uiForm.value
  const { id } = row
  ElMessageBox({
    title: '提示框',
    message: `确认要${actionName}${tips ? `《${tips}》` : ''}？`,
    showCancelButton: true,
    confirmButtonText: `确认${actionName}`,
    cancelButtonText: '取消',
    type: 'warning',
    beforeClose: (action, instance, done) => {
      if (action === 'confirm') {
        instance.confirmButtonLoading = true
        instance.confirmButtonText = `${actionName}中...`
        CustomRequest({
          url: api,
          method: 'delete',
          params: { id }
        })
          .then(({ data }) => {
            if (data && data.forms && data.forms.length) {
              // 把数据发送给父级
              mittBus.emit('onUpdateParent', data)
            }
          })
          .finally(done)
      } else {
        done()
      }
    }
  })
    .then(() => {
      onFetch()
    })
    .catch(() => ElMessage.info('已取消'))
}

/**
 * 入库
 */
const handleSoldOut = (row?: TypedAny) => {
  modalRef.value.open('0', row)
}

/**
 * 出库
 */
const handleSell = () => {
  const radio = unref(gridRef)?.getRadioRecord()
  if (radio) {
    if (radio && radio.set_type_count === '0') {
      modalRef.value.open('1', radio)
    } else ElMessage.warning('请勾选入库单。')
  } else {
    ElMessage.warning('未勾选入库单。')
  }
}

onBeforeMount(() => {
  if (route.query.id) {
    modelValue.value = String(route.query.id)
  } else if (!modelValue.value) modelValue.value = String(route.meta.id)
  onFetchBusiness()
})
</script>

<template>
  <div class="layout-padding">
    <vxe-toolbar ref="toolbarRef" v-bind="toolbarConfig">
      <template #buttons>
        <slot>
          <TemplateQuery
            v-if="uiTable"
            v-model="loading"
            ref="queryRef"
            :ui-query="uiQuery"
            :ui-actions="uiActions"
            :dic-query="dicQuery"
            :right-spacing="rightSpacing"
            :show-actions="['reload']"
            @action="onAction"
            @fetch="onToolFetch"
          >
            <template #query_default>
              <el-button :icon="SoldOut" type="success" @click="handleSoldOut()">
                新增入库
              </el-button>
              <el-button :icon="Sell" type="warning" @click="handleSell"> 新增出库</el-button>
              <el-tag>合计量：{{ queryNum }}</el-tag>
            </template>
          </TemplateQuery>
        </slot>
      </template>
    </vxe-toolbar>
    <div class="layout-padding-auto layout-padding-view">
      <vxe-grid
        ref="gridRef"
        v-bind="gridOptions"
        height="auto"
        :data="gridData"
        :loading="loading"
        @custom="onCustomChange"
        @resizable-change="onResizableChange"
      >
        <!-- 标签 -->
        <template #el_tag="{ row, column }">
          <el-tag :type="row[`${column.field}_display_type`] || 'info'">
            {{ row[column.field] }}
          </el-tag>
        </template>
        <!-- 操作 -->
        <template #action="{ row }">
          <el-space :size="5">
            <el-button
              v-for="(action, index) in embeddedUIActions"
              :key="index"
              size="small"
              :type="action.type || 'default'"
              :disabled="action.action === 'finish' ? row[action.action] === '是' : false"
              :class="{
                'opacity-0-3': action.action === 'finish' ? row[action.action] === '是' : false
              }"
              @click.stop="onAction(action, row)"
              link
            >
              {{ action.name }}
            </el-button>
          </el-space>
        </template>
        <!-- pager 插槽-->
        <template #pager v-if="uiTable?.pagination">
          <vxe-pager
            :layouts="
              mobile
                ? ['PrevJump', 'PrevPage', 'Number', 'NextPage', 'Total']
                : [
                    'Sizes',
                    'PrevJump',
                    'PrevPage',
                    'Number',
                    'NextPage',
                    'NextJump',
                    'FullJump',
                    'Total'
                  ]
            "
            v-model:current-page="gridPage.page"
            v-model:page-size="gridPage.pageSize"
            :total="gridPage.total"
            @page-change="onFetch()"
          >
          </vxe-pager>
        </template>
      </vxe-grid>
    </div>
    <ProductViewModal ref="modalRef" :dic-table="dicTable" :ui-form="uiForm" @fetch="onFetch()" />
  </div>
</template>
